#pragma once
#include <vector>
#include <vector>
#include <utility>
#include <fstream>
#include <sstream>
#include <algorithm>
using namespace std;

#include "../renderer/Sprite.h"
#include "../frame/frame.h"
#include "../basiclib/Common.h"
#include "../basiclib/camera.h"
#include "../basiclib/texture.h"
#include "../basiclib/ui.h"
#include "../basiclib/font.h"
#include "../basiclib/String.h"
#include "../basiclib/animPlayer.h"
#include "../basiclib/collision.h"
#include "../game/state.h"
#include "../game/gameObj.h"

namespace TGO
{
	//constants
	const float	atom_size			= 32;
	const float chatTrigger_len		= 32;

	void						OnInit();
	void						OnUpdate( float dt );
	void						OnMainLoop();
	void						OnRelease();

	//different layers
	D3DXVECTOR3					MapMidLayer( D3DXVECTOR2 pos );
	D3DXVECTOR3					MapBkgLayer( D3DXVECTOR2 pos );
	D3DXVECTOR3					MapPkgLayer( D3DXVECTOR2 pos );

	//transform between row&col and pos
	D3DXVECTOR2					RowColToPos( int r, int c, int midR, int midC );

	//cmp methods
	bool						CmpTgo2DEntity( Tgo2DEntity* e1, Tgo2DEntity* e2 );
	//in rect
	bool						InRect( D3DXVECTOR2 pos, RECT r );
	//reverse
	string						Reverse( string anim );

	class Game;
	Game&						God();
	class FriendRole;
	FriendRole&					MainRole();

	struct Atom
	{
								Atom() { };
								Atom( string texID, RECT texArea ):mTexID( texID ), mTexArea( texArea ) { }
								Atom( const Atom& rhs ) { mTexID = rhs.mTexID; mTexArea = rhs.mTexArea; mIsCollide = rhs.mIsCollide; }

		string					mTexID;
		RECT					mTexArea;
		bool					mIsCollide;
	};

	struct PotralState
	{
								PotralState() { };
								PotralState( string map, D3DXVECTOR2 pos, string anim, RECT area )
									:mMap( map ), mPos( pos ), mAnim( anim ), mArea( area ) { }
								PotralState( const PotralState& rhs ) {
									mMap = rhs.mMap;
									mPos = rhs.mPos;
									mAnim = rhs.mAnim;
									mArea = rhs.mArea;
								}
		string					mMap;
		D3DXVECTOR2				mPos;
		string					mAnim;
		RECT					mArea;
	};

	class Map
	{
	public:
		static void				LoadMap( const string map, Sprite& renderer, vector<Role*>& roles );

		static void				SetMapAtom( int r, int c, bool val );
		static void				SetMapAtom( D3DXVECTOR2 pos, bool val );
		static bool				GetMapAtom( int r, int c );
		static bool				GetMapAtom( D3DXVECTOR2 pos );
		static pair< int, int > CollisionAtom() {
			if ( mCollisionAtoms.second <= 0 ) {
				mCollisionAtoms.first = mNPCs.first;
			}
			return pair<int, int>( mCollisionAtoms.first, mMonsters.second ); }
		static vector< PotralState > Potrals() {
			return mPotrals;
		}

		static bool				ConstraintCamera( D3DXVECTOR3& pos );
		static bool				IsCollide( Role& role );
		static int				LayerCnts() { return mLayerCnts; }
		static RECT				MapCameraArea() { return mArea; }
	private:		
		static void				ReadMap( ifstream& fin, Sprite& renderer );
		static void				ReadRolesPotrals( ifstream& fin, Sprite& renderer, vector<Role*>& roles );

		static string			mMapName;
		static int				mRows;
		static int				mCols;
		static RECT				mArea;
		static size_t			mLayerCnts;

		static pair< int, int > mCollisionAtoms;
		static pair< int, int > mNormalAtoms;
		static pair< int, int >	mNPCs;
		static pair< int, int > mMonsters;
		static vector< PotralState >	mPotrals;
		static vector< vector< bool > > mMap;
		static vector<CollisionBox>		mCollisionBox;
	};

	bool						GameWndProc( UINT message, WPARAM wParam, LPARAM lParam );
	bool						MainRoleWndProc( UINT message, WPARAM wParam, LPARAM lParam );

	class Game
	{
	public:
		friend	bool			GameWndProc( UINT message, WPARAM wParam, LPARAM lParam );
		friend	bool			MainRoleWndProc( UINT message, WPARAM wParam, LPARAM lParam );

		void					OnInit();
		void					OnUpdate( float dt );
		void					OnMainLoop();
		void					OnRelease();

		vector< Role* >&		RoleList() { return mRole; }
	private:
		void					InitConfig();
		void					InitFont();
		void					InitTextures( string texturesFile );
		void					InitAnims( string animFile );
		void					InitMainRole();
		void					InitUI();
		void					InitStartMenu();

		void					UpdateRenderer( float dt );
		void					UpdateRole( float dt );
		void					UpdateCamera( float dt );
		void					UpdateUI( float dt );

		void					MainLoopRenderer();
		void					MainLoopUI();
		void					MainLoopDialog();

		void					ReleaseSprite();
		void					ReleaseUI();
		void					ReleaseRoleList();

		void					ActiveUI( int idUI );
		void					DeActiveUI( int idUI );

		vector< vector< TgoUIBase* > >	mUIs;

		Sprite					mRenderer;
		vector< Role* >			mRole;
	};

	class DialogPlayer
	{
	public:
		static bool					IsThereATalk() { return mIsHasTalk; }
		static void					IsATalk( int id ) { TalkTips->Active(); mIsHasTalk = true; mTalkID = id; }
		static void					IsNoTalk() { TalkTips->DeActive(); mIsHasTalk = false; }
		static int					TalkID() { return mTalkID; }

		static void					StartDialog() { TalkTips->DeActive(); DialogBox->Active(); mDialogPtr = 0;mDisplayPtr = 0; mIsDialogEnd = false; }
		static void					EndDialog() { DialogBox->DeActive(); mIsDialogEnd = true; }
		static bool 				IsDialogEnd() { return mIsDialogEnd; }
		static void					SetDialog();
		static void					NextDialog();
		static String				DisplayDialog();

		static void					LoadDialogs( string dialogList );
	public:
		static TgoUIBase*			DialogBox;
		static TgoUIBase*			TalkTips;
	private:
		static bool					mIsHasTalk;
		static bool					mIsDialogEnd;
		static int					mTalkID;
		static int					mDialogPtr;
		static int					mDisplayPtr;
		static vector< String >		mDialog;
		static map< int, vector< String > >	mDialogList;
	};

}